<html>
<head>
    <title>Tree list dev</title>
<script type="text/javascript" src="../jquery/jquery.js">
</script>
<style>
#treelist {
  border: 1px solid gray;
}

.treelist-header {
  background-color: silver;
}

.treelist-header-row {
}

.treelist-header-cell {
  border: 1px solid white;
}

.treelist-body {
  cursor: default;
}

.treelist-row {
}

.treelist-cell {
}

.treelist-row-highlight {
  background-color: #e0e0ff;
}

.treelist-node-indent {
  margin-left: 16px;
}

.treelist-collapse-icon {
  background-image: url(./tree_minus.gif);
}

.treelist-expand-icon {
  background-image: url(./tree_plus.gif);
}

.treelist-folder-icon {
  background-image: url(./folder.gif);
}

.treelist-folder-open-icon {
  background-image: url(./folder-open.gif);
}

.treelist-file-icon {
  background-image: url(./file.gif);
}
</style>

<script type="text/javascript">
var script_absolute_path = "./";

(function($) {

var defaultOptions = {
    headerClass: "treelist-header",
    headerColumnClass: "treelist-header-column",
    bodyClass: "treelist-body",
    bodyRowClass: "treelist-body-row",
    colTagClass: "tl-tag-col",
    rowTagClass: "tl-tag-row",
    rowChildrenTagClass: "tl-tag-row-children",
    cellTagClass: "tl-tag-cell",
    expandImageClass: "treelist-expand-icon",
    collapseImageClass: "treelist-collapse-icon",
    folderImageClass: "treelist-folder-icon",
    folderOpenImageClass: "treelist-folder-open-icon",
    fileImageClass: "treelist-file-icon",
    toggleDelay: 0,
    additionalTreeWidth: 32,
    columnWidth: 120
};

$.fn.extend({treelist: function(options){

var tlOptions = $.extend({}, defaultOptions, options);

var basePath = script_absolute_path;
var blankImage = basePath + "blank.gif";
var blankImageTag = "<img width=\"16\" height=\"0\" src=\""
    + blankImage + "\"/>";

this.each(function() {

var me = $(this);
if (me.data("treelistOpt"))
    return true;

me.css({
    "overflow-x": "auto",
    "overflow-y": "hidden"
}).bind("selectstart", function(){return false;});

if (tlOptions.width) {
    me.width(tlOptions.width);
}
if (tlOptions.height) {
    me.height(tlOptions.height);
}

//Append headers. Only single-level header is supported.
function buildHeader(opt) {
    var header = $("<div></div>");
    var ds = opt.dataSource;
    me.append(header);
    me.data("header", header.get(0));
    header.css({
        "overflow": "auto"
    }).addClass(ds.header.className || opt.headerClass);
    if (ds.header.columns && ds.header.columns.length) {
        var treeWidth = opt.additionalTreeWidth;
        for (var i = 0; i < ds.header.columns.length; i ++) {
            var col = ds.header.columns[i];
            col.width = col.width || ds.header.columnWidth || opt.columnWidth;
            treeWidth += col.width;
            var colobj = $("<span>" + col.innerHTML + "</span>").appendTo(header)
                .addClass(col.className || ds.header.columnClass || opt.headerColumnClass)
                .width(col.width)
                .css({"display": "-moz-inline-box", "display": "inline-block"})
                .addClass(opt.colTagClass);
        }
        header.width(treeWidth);
        if (!opt.width)
            me.width(treeWidth);
    }
}//End of function "buildHeader".

function adjustCellWidths(rowObj) {
    var opt = tlOptions;
    var i = 0;
    rowObj.children("." + opt.cellTagClass).each(function(){
        var margin = rowObj.data("row").level * 16;
        var w = i < opt.dataSource.header.columns.length ?
            opt.dataSource.header.columns[i].width :
            opt.columnWidth;
        if (i == 0) {
            $(this).width(w - margin);
        } else {
            $(this).width(w);
        }
        i ++;
    });
}//End of function "adjustCellWidths".

function mayHaveChildren(row) {
    return row.items && row.items.length || row.asyncFetch;
}

function findNodeObj(rowObj) {
    return rowObj.children("span:first");
}

function childrenFetched(rowObj, row) {
    return function(data) {
        row.asyncFetch = false;
        row.fetching = false;
        try {
            eval("row.items = " + data + ";");
        } catch (e) {
            if (!row.items)
                row.items = [];
        }
        expand(rowObj);
    };
}//End of function "childrenFetched".

function expand(rowObj) {
    var opt = tlOptions;
    var row = rowObj.data("row");
    if (row.asyncFetch) {
        if (!row.fetching) {
            row.fetching = true;
            $.ajax({
                url: row.fetchUrl || opt.fetchUrl,
                data: row.fetchParams,
                cache: false,
                success: childrenFetched(rowObj, row)
            });
        }
    } else {
        if (!rowObj.parent().children("div." + opt.rowChildrenTagClass).length) {
            appendRows(rowObj.parent(), row.items, false);
        }
        rowObj.parent().children("div." + opt.rowChildrenTagClass + ":first")
            .show(opt.toggleDelay);
        var nodeObj = findNodeObj(rowObj);
        nodeObj.children("img." + opt.expandImageClass + ":first")
            .removeClass(opt.expandImageClass)
            .addClass(opt.collapseImageClass);
        var node = nodeObj.data("node");
        node.expanded = true;
        if (!row.iconClass) {
            nodeObj.children("img." + opt.folderImageClass + ":first")
                .removeClass(opt.folderImageClass)
                .addClass(opt.folderOpenImageClass);
        }
    }
}//End of function "expand".

function collapse(rowObj) {
    var opt = tlOptions;
    rowObj.parent().children("div." + opt.rowChildrenTagClass + ":first")
        .hide(opt.toggleDelay);
    var nodeObj = findNodeObj(rowObj);
    nodeObj.children("img." + opt.collapseImageClass + ":first")
        .removeClass(opt.collapseImageClass)
        .addClass(opt.expandImageClass);
    var node = nodeObj.data("node");
    node.expanded = false;
    nodeObj.children("img." + opt.folderOpenImageClass + ":first")
        .removeClass(opt.folderOpenImageClass)
        .addClass(opt.folderImageClass);
}//End of function "collapse".

function appendRows(parentObj, items, visible) {
    if (!items || !items.length)
        return;
    var opt = tlOptions;
    var parentRowObj = parentObj.children("div." + opt.rowTagClass + ":first");
    var level = parentRowObj.data("row") ? parentRowObj.data("row").level + 1 : 0;
    var children = $("<div></div>")
        .css({
            "overflow": "hidden",
            "display": (visible ? "" : "none")
        })
        .appendTo(parentObj)
        .addClass(opt.rowChildrenTagClass);
    if (level > 0) {
        children.css({"margin-left": "16px"});
    }
    var ds = opt.dataSource;
    for (var i = 0; i < items.length; i ++) {
        var row = items[i];
        var prow = parentObj.children("div:first");
        row.level = level;
        var currentRow = $("<div></div>")
            .appendTo(children);
        var rowObj = $("<div></div>")
            .css({"overflow": "hidden"})
            .addClass(row.className || ds.body.rowClass || opt.bodyRowClass)
            .appendTo(currentRow)
            .addClass(opt.rowTagClass)
            .data("row", row);
        var node = row.cells[0];
        var mhc = mayHaveChildren(row);
        var nodeStr = "<span><img width=\"16\" height=\"16\" src=\""
            + blankImage + "\" class=\""
            + (mhc ? opt.expandImageClass : "") + "\"/><img width=\"16\" height=\"16\" src=\""
            + blankImage + "\" class=\""
            + (row.iconClass || 
                (mhc ? opt.folderImageClass : opt.fileImageClass)
                || "") + "\"/>"
            + node.innerHTML + "</span>";
        var nodeObj = $(nodeStr);
        nodeObj.data("node", node)
            .addClass(opt.cellTagClass);
        if (mhc) {
            node.expanded = false;
            nodeObj.children("img." + opt.expandImageClass).click(function(){
                if ($(this).parent().data("node").expanded) {
                    collapse($(this).parent().parent());
                } else {
                    expand($(this).parent().parent());
                }
            });
        }
        nodeObj.css({
            "white-space": "nowrap",
            "overflow": "hidden",
            "display": "-moz-inline-box",
            "display": "inline-block"
        })
            .addClass(node.className || row.cellClass
                || ds.body.cellClass || opt.bodyCellClass
                || "")
            .appendTo(rowObj);
        for (var j = 1; j < row.cells.length; j ++) {
            var cell = row.cells[j];
            var cellObj = $("<span>" + cell.innerHTML + "</span>")
                .addClass(cell.className || row.cellClass
                    || ds.body.cellClass || opt.bodyCellClass
                    || "")
                .css({
                    "white-space": "nowrap",
                    "overflow": "hidden",
                    "display": "-moz-inline-box",
                    "display": "inline-block"
                })
                .appendTo(rowObj)
                .addClass(opt.cellTagClass);
        }
        adjustCellWidths(rowObj);
        if (typeof (opt.rowAdded) == "function") {
            opt.rowAdded(row, rowObj);
        }
    }
}//End of function "appendRows".

function buildBody(opt) {
    var body = $("<div></div>");
    me.append(body);
    me.data("body", body.get(0));
    body.css({
        "overflow-y": "auto",
        "overflow-x": "hidden"
    }).addClass(opt.dataSource.body.className || opt.bodyClass);
    var header = me.data("header");
    var headerObj = $(header);
    if (opt.height) {
        body.height(me.height() - headerObj.height());
    }
    body.width(header ? ("" + headerObj.width() + "px") : "100%");
    appendRows(body, opt.dataSource.body.items, true);
}//End of function "buildBody".

if (tlOptions.dataSource) {
    if (tlOptions.dataSource.header) {
        buildHeader(tlOptions);
    } else {
        tlOptions.dataSource.header = {columns: [{}]};
    }
    if (tlOptions.dataSource.body) {
        buildBody(tlOptions);
    } else {
        tlOptions.dataSource.body = {items: []};
    }
}
return true;
});//End of "each" iteration.
this.data("treelistOpt", tlOptions);

return this;//For extension "treelist".
}//End of extension "treelist".
});//End of function "extend".

})(jQuery);
</script>

<script type="text/javascript" src="provinces.js">
</script>

<script type="text/javascript">
var ds = {
    header: {
        columnClass: "treelist-header-cell",
        columns: [{
            innerHTML: "Name",
            width: 360
        }, {
            innerHTML: "Code"
        }]
    },
    body: {
        className: "treelist-body",
        items: treebody
    }
};
function init() {
    $("#treelist").treelist({
        toggleDelay: 400,
        //width: 480,
        height: 640,
        dataSource: ds,
        bodyRowClass: "treelist-row",
        rowAdded: function(row, rowObj) {
            rowObj.mouseover(function() {
                $(this).addClass("treelist-row-highlight");
            }).mouseout(function() {
                $(this).removeClass("treelist-row-highlight");
            });
        }
    });
}

$(init);
</script>
</head>

<body>
<div id="treelist">
</div>
</body>
</html>